import bencode
import socket
import binascii
import json
import os
from pathlib import Path



# 字段类型参考：https://github.com/regulatedsyntax/qbfrt/blob/main/src/common/fastresume.rs

# 头部的?和/是防止与用户目录名重复
TORRENTS_KEY = '?/torrents'


def get_path_info (file_path):
    fast_resume_file, torrent_file = file_path
    
    with open(fast_resume_file, 'rb') as f:
        fast_resume = bencode.decode(f.read())
    path_info = {
        'info-hash': bytes.hex(fast_resume['info-hash']),
        'qBt-savePath': fast_resume['qBt-savePath'], # Optional
        'save_path': fast_resume['save_path'],
        'qBt-name': fast_resume['qBt-name']
    }
    if fast_resume['qBt-name'] == None or fast_resume['qBt-name'] == '':
        with open(torrent_file, 'rb') as f:
            torrent = bencode.decode(f.read())
        path_info['qBt-name'] = torrent['info']['name']
        
    return path_info


def build_directory_tree(path_info_list):

    tree = {}
    for path_info in path_info_list:
        path_parts = Path(path_info['save_path']).parts
        current_root = tree
        for i,part in enumerate(path_parts):
            if part in current_root:
                current_root = current_root[part]
                continue

            for _p in path_parts[i:]:
                current_root[_p] = {}
                current_root = current_root[_p]
            break
        
        if TORRENTS_KEY not in current_root:
            current_root[TORRENTS_KEY] = []
        current_root[TORRENTS_KEY].append({
            'hash': path_info['info-hash'],
            'name': path_info['qBt-name'],
        })
        
    return tree

def load(file_path_list):
    """
    parameters
    ----------
    file_path_list : list[list|tulpe]
        [(fastresume_path, torrent_path),...]
    """

    # 获取 torrent 的下载路径
    path_info_list = []    
    for file_path in file_path_list:
        path_info_list.append(get_path_info(file_path))

    # 构建目录树
    directory_tree = build_directory_tree(path_info_list)

    # 写入json文件
    json_str = json.dumps(directory_tree)
    with open('./origin_directory.json', 'w', encoding='utf-8') as f:
        f.write(json_str)

def from_dir(files_dir):
    # 获取BT_backup下所有的fastresume文件的绝对路径
    file_list = sorted(os.listdir(files_dir))
    file_list = file_list[:-1] # remove queue file
    file_path_list = []
    for i in range(0, len(file_list), 2):
        f = os.path.normpath(os.path.join(files_dir, file_list[i]))     # fastresume
        t = os.path.normpath(os.path.join(files_dir, file_list[i+1]))   # torrent
        file_path_list.append((f, t))

    load(file_path_list)

def mv(directory_tree:dict, src:str, desc:str):
    """
    parameters
    ----------

    src : `str`
        C:\\\u8fc5\u96f7\u4e0b\u8f7d\\P\\US\\Bishoujomom[hash value]
        or 
        C:\\\u8fc5\u96f7\u4e0b\u8f7d\\P\\US\\Bishoujomom
    """
    if src[-1] == ']':
        mv_torrent(directory_tree, src, desc)
    else:
        mv_directory(directory_tree, src, desc)
    

def mv_directory(directory_tree:dict, src:str, desc:str):
    """
    parameters
    ----------

    src : `str`
        C:\\\u8fc5\u96f7\u4e0b\u8f7d\\P\\US\\Bishoujomom
    """

    # extract the parent directory
    src = Path(src).resolve()
    src_parent = str(src.parent)
    src_name = src.name

    # get nearest directory
    src_dir = get_dir(directory_tree, src_parent)
    desc_dir = get_dir(directory_tree, desc)

    # remove from src_dir
    # added to desc_dir
    desc_dir[src_name] = src_dir.pop(src_name)

    print(f'mv {src} {desc}\\{src_name}')



def mv_torrent(directory_tree:dict, src:str, desc:str):
    """
    parameters
    ----------

    src : `str`
        C:\\\u8fc5\u96f7\u4e0b\u8f7d\\P\\US\\Bishoujomom[hash value]
    """

    # extract path and hash
    index = str.rfind(src, '[')
    torrent_hash = int(src[index+1:-1])
    src = src[:index]

    # get nearest directory
    src_dir = get_dir(directory_tree, src)
    desc_dir = get_dir(directory_tree, desc)

    # locate by hash
    torrent = None
    index = 0
    for i,t in enumerate(src_dir[TORRENTS_KEY]):
        if t['hash'] == torrent_hash:
            torrent = t
            index = i
            break
    
    # remove from src
    src_dir[TORRENTS_KEY].pop(index)

    # added to desc
    if TORRENTS_KEY not in desc_dir:
        desc_dir[TORRENTS_KEY] = [torrent]
    else:
        desc_dir[TORRENTS_KEY].append(torrent)
    
    print(f'mv {src}\\{torrent["name"]} {desc}\\{torrent["name"]}')
    
def get_dir(directory_tree:dict, path:Path|str)->dict:
    _path = Path(path).resolve()
    _path_dir = directory_tree
    for part in _path.parts:
        if part not in _path_dir:
            _path_dir[part] = {}
        _path_dir = _path_dir[part]
    return _path_dir

if  __name__ == '__main__':
    BT_backup = r'./BT_backup'
    from_dir(BT_backup)
    
    # t = './BT_backup/3d79e0344f5eb28efc701559ac6b2c1981dbc5bd.torrent'
    # with open(t, 'rb') as f:
    #     content = f.read()
    # cc = bencode.decode(content)

    # file = r"./0b67efc7464644eba4b3b23f6198ffaffe639487.fastresume"
    # get_path_info(file)

    # peers = b'%0_8\xb9\x13'
    # peer_list = decode_peer_info(peers)
    # print("Decoded Peers:", peer_list)

    # encoded_peers = encode_peer_info(peer_list)
    # print("Encoded Peers:", encoded_peers)

    # from pathlib import Path
    # path = 'C:\\迅雷下载\\P\\US\\Bishoujomom'
    # p = Path(path)

    print('done.')











# 尝试按照常见的对等节点信息格式解码
def decode_peer_info(peers):
    peer_list = []
    # 假设每个对等节点信息是6字节（IPv4地址为4字节，端口号为2字节）
    for i in range(0, len(peers), 6):
        chunk = peers[i:i+6]
        if len(chunk) == 6:
            ip_bytes = chunk[:4]
            port_bytes = chunk[4:]
            ip = socket.inet_ntoa(ip_bytes)
            port = int.from_bytes(port_bytes, byteorder='big')
            peer_list.append((ip, port))
    return peer_list

# 将对等节点列表编码为字节字符串
def encode_peer_info(peer_list):
    encoded_peers = b''
    for peer in peer_list:
        ip, port = peer
        # 将IP地址转换为字节
        ip_bytes = socket.inet_aton(ip)
        # 将端口号转换为字节（大端序）
        port_bytes = port.to_bytes(2, byteorder='big')
        # 将IP和端口字节添加到编码后的对等节点列表中
        encoded_peers += ip_bytes + port_bytes
    return encoded_peers
